package top.jianx.storage.template;

import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import io.minio.MinioClient;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import top.jianx.storage.dto.BaseFile;
import top.jianx.storage.props.StorageProperties;
import top.jianx.storage.rule.StorageRule;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

/**
 * 〈Minio〉
 *
 * @since: 1.0.0
 * @author: Jianx
 * @date: 2021/3/27
 */
@Slf4j
@AllArgsConstructor
public class MinioTemplate implements StorageTemplate {
    private final MinioClient minioClient;
    private final StorageProperties properties;
    private final StorageRule ossRule;

    @Override
    @SneakyThrows
    public void makeBucket(String bucketName) {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(getBucketName(bucketName));
        }
    }

    @Override
    @SneakyThrows
    public boolean bucketExists(String bucketName) {
        return minioClient.bucketExists(getBucketName(bucketName));
    }

    @Override
    @SneakyThrows
    public String fileLink(String fileName, String bucketName, boolean timelines) {
        if (timelines) {
            return minioClient.presignedPutObject(bucketName, fileName, properties.getStorageFile().getTimeLiness()).toString();
        }
        return getOssHost(bucketName).concat(StringPool.SLASH).concat(fileName);
    }

    @Override
    @SneakyThrows
    public String fileLink(String fileName, String bucketName, boolean timelines, Integer timeliness) {
        if (timelines) {
            return minioClient.presignedPutObject(bucketName, fileName, timeliness).toString();
        }
        return getOssHost(bucketName).concat(StringPool.SLASH).concat(fileName);
    }

    @Override
    @SneakyThrows
    public BaseFile putFile(String bucketName, String module, String originalName, MultipartFile file) {
        return putFile(bucketName, module, originalName, file.getInputStream());
    }

    @Override
    @SneakyThrows
    public BaseFile putFile(String bucketName, String module, String originalName, InputStream inputStream) {
        return put(bucketName, module, inputStream, originalName, properties.getStorageRule().getIsCover());
    }

    /**
     * 上传文件
     *
     * @param bucketName   存储桶名称
     * @param stream       上传文件InputStream
     * @param originalName 上传文件key
     * @param cover        是否覆盖
     * @return BaseFile
     */
    @Override
    @SneakyThrows
    public BaseFile put(String bucketName, String module, InputStream stream, String originalName, boolean cover) {
        makeBucket(bucketName);
        String key = getFileName(module, originalName);
        byte[] bytes = IoUtil.readBytes(stream);
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        // 覆盖上传
        if (cover) {
            minioClient.putObject(getBucketName(bucketName), key, bis, bis.available(),"application/octet-stream");
        } else {
            minioClient.putObject(getBucketName(bucketName), key, bis, bis.available(), "application/octet-stream");
        }
        BaseFile file = getObject(bucketName, key);
        file.setOriginalFileName(originalName);
        log.debug("文件上传成功:{}", file.toString());
        return file;
    }

    /**
     * 删除文件
     *
     * @param fileName   文件名称
     * @param bucketName 存储桶名称
     */
    @Override
    @SneakyThrows
    public void removeFile(String bucketName, String fileName) {
        minioClient.removeObject(getBucketName(bucketName), fileName);
    }

    /**
     * 根据规则生成存储桶名称规则
     *
     * @param bucketName 存储桶名称
     * @return String
     */
    @Override
    public String getBucketName(String bucketName) {
        return ossRule.bucketName(bucketName);
    }

    /**
     * 根据规则生成文件名称规则
     *
     * @param module module名(桶下面的目录)
     * @param originalFilename 原始文件名
     * @return string
     */
    @Override
    public String getFileName(String module, String originalFilename) {
        return ossRule.fileName(module, originalFilename);
    }

    /**
     * 获取oss host
     *
     * @param bucketName 存储桶名称
     * @return String
     */
    @Override
    public String getOssHost(String bucketName) {
        String prefix = properties.getEndpoint().contains("https://") ? "https://" : "http://";
        return prefix + properties.getEndpoint().replaceFirst(prefix, StringPool.EMPTY) + StringPool.SLASH + getBucketName(bucketName);
    }

    /**
     * 获取文件流
     *
     * @param bucketName 存储桶
     * @param fileName   文件全路径
     * @return
     */
    @Override
    @SneakyThrows
    public BaseFile getObject(String bucketName, String fileName) {
        InputStream objectContent = minioClient.getObject(bucketName, fileName);
        BaseFile baseFile = new BaseFile();
        baseFile.setFileName(fileName)
                .setFilePath(fileLink(fileName, bucketName, false))
                .setBucketName(bucketName)
                .setObjectContent(IoUtil.readBytes(objectContent))
                .setInputStream(objectContent);
        return baseFile;
    }
}
